<?php
/*
 * SQL 查询安全过滤
 */
if(!defined('IN_KKFRAME')) exit();

function sql_safecheck($args) {
	$sql = $args[1];
	static $checkcmd = array('SELECT', 'UPDATE', 'INSERT', 'REPLACE', 'DELETE');
	$cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));
	if (in_array($cmd, $checkcmd)) {
		if (_do_query_safe($sql) < 1) {
			error::db_error('It is not safe to do this query', $sql);
		}
	}
}

function _do_query_safe($sql) {
	static $dfunction = array('load_file', 'hex', 'substring', 'if', 'ord', 'char');
	static $daction = array('intooutfile', 'intodumpfile', 'unionselect', '(select', 'unionall', 'uniondistinct');
	static $dnote = array('/*', '*/', '#', '--', '"');
	$sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);
	$mark = $clean = '';
	if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false) {
		$clean = preg_replace("/'(.+?)'/s", '', $sql);
	} else {
		$len = strlen($sql);
		$mark = $clean = '';
		for ($i = 0; $i < $len; $i++) {
			$str = $sql[$i];
			switch ($str) {
				case '\'':
					if (!$mark) {
						$mark = '\'';
						$clean .= $str;
					} elseif ($mark == '\'') {
						$mark = '';
					}
					break;
				case '/':
					if (empty($mark) && $sql[$i + 1] == '*') {
						$mark = '/*';
						$clean .= $mark;
						$i++;
					} elseif ($mark == '/*' && $sql[$i - 1] == '*') {
						$mark = '';
						$clean .= '*';
					}
					break;
				case '#':
					if (empty($mark)) {
						$mark = $str;
						$clean .= $str;
					}
					break;
				case "\n":
					if ($mark == '#' || $mark == '--') {
						$mark = '';
					}
					break;
				case '-':
					if (empty($mark) && substr($sql, $i, 3) == '-- ') {
						$mark = '-- ';
						$clean .= $mark;
					}
					break;
				default:
					break;
			}
			$clean .= $mark ? '' : $str;
		}
	}
	$clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));
	$clean = str_replace('/**/', '', $clean);
	foreach ($dfunction as $fun) {
		if (strpos($clean, $fun.'(') !== false) return '-1';
	}

	foreach ($daction as $action) {
		if (strpos($clean, $action) !== false) return '-3';
	}
	if (strpos($clean, 'like0x')) return '-2';
	foreach ($dnote as $note) {
		if (strpos($clean, $note) !== false) return '-4';
	}
	return 1;
}

HOOK::register('mysql_query', 'sql_safecheck');
